package com.oswift.utils.file;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

import net.sf.zipme.ZipEntry;
import net.sf.zipme.ZipOutputStream;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.oswift.utils.common.StreamUtil;

/**
 *
 * zipme压缩算法工具类
 *
 * @author zhuou
 * @version C03 Oct 27, 2012
 * @since OSwift GPM V1.0
 */
public final class Zipme
{
    /**
     * 获取日志对象
     */
    private static Logger log = LoggerFactory.getLogger(Zipme.class);

    private Zipme()
    {
    }

    /**
     * 对指定文件路径递归压缩到压缩文件中
     *
     * @param dst
     *            String 压缩文件路径，
     * @param src
     *            String 文件路径，文件或文件夹
     *
     * @return boolean 成功 - true，失败 - false
     */
    public static boolean zip(String dst, String src)
    {
        boolean result = false;

        ZipOutputStream zipOutputStream = null;
        FileOutputStream fileOutputStream = null;

        try
        {
            // 创建压缩输出流
            fileOutputStream = new FileOutputStream(new File(dst));
            zipOutputStream = new ZipOutputStream(fileOutputStream);

            // 压缩
            compress(new File(src), zipOutputStream);

            result = true;
        }
        catch (IOException e)
        {
            log
                    .error("Fail to zip src file:" + src + " to dest file:"
                            + dst, e);
            result = false;
        }
        finally
        {
            StreamUtil.getInstance().close(zipOutputStream, fileOutputStream);
        }

        return result;
    }

    /**
     * 压缩
     *
     * @param file
     *            File
     * @param zipOutputStream
     *            ZipOutputStream
     * @throws IOException
     */
    private static void compress(File file, ZipOutputStream zipOutputStream)
        throws IOException
    {
        if (file.isDirectory())
        {
            compress(file, zipOutputStream, "");
        }
        else
        {
            compress(file, zipOutputStream, file.getName());
        }
    }

    /**
     * 压缩
     *
     * @param file
     *            File
     * @param zipOutputStream
     *            ZipOutputStream
     * @param zipEntryName
     *            String
     * @throws IOException
     */
    private static void compress(File file, ZipOutputStream zipOutputStream,
            String zipEntryName) throws IOException
    {
        if (file.isDirectory())
        {
            File[] subfiles = file.listFiles();

            try
            {
                if (0 != zipEntryName.length())
                {
                    zipEntryName = zipEntryName + "/";
                    zipOutputStream.putNextEntry(new ZipEntry(zipEntryName));
                }
            }
            catch (IOException e)
            {
                throw e;
            }
            for (File subfile : subfiles)
            {
                // 递归调用
                compress(subfile, zipOutputStream, zipEntryName
                        + subfile.getName());
            }
        }
        else
        {
            FileInputStream fis = null;
            try
            {
                zipOutputStream.putNextEntry(new ZipEntry(zipEntryName));
                fis = new FileInputStream(file);
                final int initSize = 4096;
                byte[] buffer = new byte[initSize];
                int length = 0;

                while (-1 != (length = fis.read(buffer)))
                {
                    zipOutputStream.write(buffer, 0, length);
                }
            }
            catch (FileNotFoundException e)
            {
                log.error("File [" + file + "] not found.");
                throw e;
            }
            catch (IOException e)
            {
                throw e;
            }
            finally
            {
                StreamUtil.getInstance().close(fis);
            }
        }
    }
}
